#!/usr/bin/env python3

import rospy
from std_msgs.msg import String
from playsound import playsound
import time
import os

class PlayVoice:
    def __init__(self, audio_base_path): # 构造函数现在接受一个参数
        # 验证传入的路径是否是绝对路径，或者让它成为绝对路径
        if not os.path.isabs(audio_base_path):
            # 如果是相对路径，我们把它相对于当前工作目录解析为绝对路径
            # 这样无论从哪里运行rosrun，路径都会是确定的
            audio_base_path = os.path.abspath(audio_base_path)
            
        # 检查目录是否存在，如果不存在则创建
        if not os.path.exists(audio_base_path):
            try:
                os.makedirs(audio_base_path, exist_ok=True)
                rospy.loginfo(f"Audio directory '{audio_base_path}' created.")
            except OSError as e:
                rospy.logerr(f"Error creating audio directory '{audio_base_path}': {e}")
                raise ValueError(f"Failed to create specified audio path: {audio_base_path}")

        self.file_path = audio_base_path
        self.allowed_colors = ["red", "yellow", "orange", "blue"]
        self.allowed_dashboards = ["1", "2", "3"]
        self.allowed_states = ["normal", "high", "low"]

        rospy.loginfo(f"PlayVoice initialized. Audio path: {self.file_path}")
        rospy.loginfo(f"Allowed colors: {self.allowed_colors}")
        rospy.loginfo(f"Allowed dashboards: {self.allowed_dashboards}")
        rospy.loginfo(f"Allowed states: {self.allowed_states}")

    def play(self, color, dashboard, state):
        ''' Check if the color, dashboard, and state are valid, then play the corresponding audio file.'''
        try:
            if color not in self.allowed_colors:
                raise ValueError(f"Invalid color: {color}. Allowed colors are: {self.allowed_colors}")
            if dashboard not in self.allowed_dashboards:
                raise ValueError(f"Invalid dashboard: {dashboard}. Allowed dashboards are: {self.allowed_dashboards}")
            if state not in self.allowed_states:
                raise ValueError(f"Invalid state: {state}. Allowed states are: {self.allowed_states}")

            rospy.loginfo(f"Received valid parameters: color={color}, dashboard={dashboard}, state={state}")

            color_audio = f"{color}_area.mp3"
            dashboard_audio = f"dashboard_{dashboard}.mp3"
            state_audio = f"{state}.mp3"

            audio_files_to_play = [color_audio, dashboard_audio, state_audio]

            for audio_file_name in audio_files_to_play:
                full_path = os.path.join(self.file_path, audio_file_name)
                if os.path.exists(full_path):
                    rospy.loginfo(f"Playing: {full_path}")
                    playsound(full_path)
                    time.sleep(0.1) # Small pause between sounds
                else:
                    rospy.logwarn(f"Audio file '{full_path}' does not exist. Skipping.")

        except ValueError as e:
            rospy.logwarn(f"Error in play method: {e}")
        except Exception as e:
            rospy.logerr(f"An unexpected error occurred during audio playback: {e}")

class VoiceCommandNode:
    def __init__(self):
        # Initialize the ROS node
        rospy.init_node('voice_command_player', anonymous=True)

        # 尝试从参数服务器获取音频路径
        # 默认值设置为 'audio/'，如果命令行没有提供则使用此值
        audio_path_param = rospy.get_param('~audio_path', 'audio/') # ~ 表示私有参数

        # Initialize the PlayVoice instance
        try:
            self.play_voice_instance = PlayVoice(audio_base_path=audio_path_param)
        except ValueError as e:
            rospy.logerr(f"Failed to initialize PlayVoice: {e}. Exiting node.")
            rospy.signal_shutdown(f"Initialization failed: {e}")
            return

        # Create a subscriber to the 'voice_commands' topic
        self.subscriber = rospy.Subscriber('voice_commands', String, self.callback_command)
        rospy.loginfo("Voice Command Player Node initialized and subscribing to '/voice_commands' topic.")

    def callback_command(self, msg):
        """
        Callback function for the voice_commands subscriber.
        Parses the incoming string message and calls the play_voice_instance.play method.
        Expected message format: "color,dashboard,state" (e.g., "red,1,normal")
        """
        rospy.loginfo(f"Received command: '{msg.data}'")
        parts = msg.data.split(',')

        if len(parts) == 3:
            color = parts[0].strip().lower()
            dashboard = parts[1].strip()
            state = parts[2].strip().lower()
            self.play_voice_instance.play(color, dashboard, state)
        else:
            rospy.logwarn(f"Invalid command format: '{msg.data}'. Expected 'color,dashboard,state'.")

    def run(self):
        # Keep the node running until it's shut down
        rospy.spin()

if __name__ == '__main__':
    try:
        node = VoiceCommandNode()
        node.run()
    except rospy.ROSInterruptException:
        pass
    except Exception as e:
        rospy.logerr(f"Node execution failed: {e}")